package com.biz.xxljob.utils;

import com.xxl.job.core.util.*;
import lombok.extern.slf4j.*;
import org.springframework.beans.factory.*;
import org.springframework.beans.factory.annotation.*;
import org.springframework.util.*;

import java.io.*;
import java.net.*;
import java.util.*;

@Slf4j
public class XxlNetUtil implements InitializingBean {

    @Value("${xxl.job.host-address:#{null}}")
    private String hostAddress;

    @Value("${xxl.job.ignored-interfaces:#{null}}")
    private String ignoredInterfaces;

    private InetAddress inetAddress;

    @Override
    public void afterPropertiesSet() {
        this.inetAddress = findFirstNonLoopbackAddress();
        if (this.inetAddress == null) {
            this.inetAddress = IpUtil.getLocalAddress();
        }
        log.info("xxl-job host address: {}", getHostAddress());
    }

    public InetAddress getInetAddress() {
        return this.inetAddress;
    }

    public String getHostAddress() {
        if (StringUtils.isEmpty(this.hostAddress)) {
            return this.inetAddress.getHostAddress();
        }
        return this.hostAddress;
    }

    private InetAddress findFirstNonLoopbackAddress() {
        InetAddress result = null;
        try {
            int lowest = Integer.MAX_VALUE;
            Enumeration<NetworkInterface> interfaces = NetworkInterface.getNetworkInterfaces();
            while (interfaces.hasMoreElements()) {
                NetworkInterface network = interfaces.nextElement();
                if (network.isUp() && !network.isLoopback() && !network.isVirtual()) {
                    if (network.getIndex() < lowest || result == null) {
                        lowest = network.getIndex();
                    } else if (result != null) {
                        continue;
                    }
                    // 网卡忽略逻辑
                    if (!ignoreInterface(network.getDisplayName())) {
                        Enumeration<InetAddress> addresses = network.getInetAddresses();
                        while (addresses.hasMoreElements()) {
                            InetAddress address = addresses.nextElement();
                            // ip忽略逻辑
                            if (address instanceof Inet4Address && !address.isLoopbackAddress()) {
                                log.info("Found non-loopback interface: {}", network.getDisplayName());
                                result = address;
                            }
                        }
                    }
                }
            }
        } catch (IOException ex) {
            log.error("Cannot get first non-loopback address: {}", ex.getMessage());
        }

        if (result != null) {
            return result;
        }

        // 当规则匹配不到ip时候, 直接使用该逻辑获取信息
        try {
            return InetAddress.getLocalHost();
        } catch (UnknownHostException e) {
            log.warn("Unable to retrieve localhost");
        }
        return null;
    }

    boolean ignoreInterface(String interfaceName) {
        if (this.ignoredInterfaces != null) {
            String[] interfaceNames = StringUtils.tokenizeToStringArray(this.ignoredInterfaces, ",| ");
            if (interfaceNames != null) {
                for (String regex : interfaceNames) {
                    if (interfaceName.matches(regex)) {
                        log.trace("Ignoring interface: " + interfaceName);
                        return true;
                    }
                }
            }
        }
        return false;
    }
}
